#ifndef __ELEMENT_H__
#define __ELEMENT_H__

#include "mesh.h"

// 结构体: 单元
typedef struct ELEMENT_
{
    INT worlddim;
    INT NumVerts;
    DOUBLE *Vert_X;
    DOUBLE *Vert_Y;
    DOUBLE *Vert_Z;
    DOUBLE Volumn;
    DOUBLE  Jacobian[3][3];
    DOUBLE  InvJacobian[3][3];
    // 一些特殊的单元用到的信息
    INT VertIdInRefElem[4]; // 按照全局编号顺序由小到大排列的各个点在原标准单元中的编号
    INT LineIdInRefElem[6]; // 按照全局编号顺序由小到大排列的各个线在原标准单元中的编号(负号为反向)
    // BOOL if_line_positive[6]; // 记录单元每条边的局部编号方向是否是正向(线的方向)的
    // BOOL if_norm_positive[4]; // 记录单元每个面的局部编号对应外法向是否是正向(线的外法向)的
    // 记录单元种类或需要计算哪些信息
    BOOL is_curl; // 记录单元是否为curl单元
    BOOL is_div; // 记录单元是否为div单元
    BOOL is_det_positive; // 记录单元的det是否为正
} ELEMENT;

void ElementRefCoord2Coord(ELEMENT *Elem, DOUBLE RefCoord[], DOUBLE Coord[]);
ELEMENT *ElementInitial(MESH *mesh);
void ElementBuild(MESH *mesh, INT Index, ELEMENT *Elem);
void CurlElementBuild(MESH *mesh, INT Index, ELEMENT *Elem);
void ComputeElementJacobian(ELEMENT *Elem);
void ComputeElementInvJacobian(ELEMENT *Elem);

// lhc 23.01.28
// 提前获取该网格的所有单元的Jacobi的逆矩阵 并按照单元编号储存
void ComputeInvJacobiOfAllElem(MESH *mesh, BOOL is_curl);
// 释放计算出的Jacobian信息
void DestroyInvJacobiOfAllElem(MESH *mesh);

void ElementDestroy(ELEMENT **Elem);
void ElementPrint(ELEMENT *Elem);
//==============================================================================================
// 下面是针对Element计算的一些几何量
// 对单元elem，计算单元每个边的外法向量，并将其按照边的012编号顺序排列至数组NormalVec中
// 设0号边外法向量为(n0x,n0y),1号边外法向量为(n1x,n1y),2号边外法向量为(n2x,n2y),
// NormalVec=[n0x,n0y,n1x,n1y,n2x,n2y]
// 三维的情况是计算每个面的外法向, 按照面的顺序来计算
void ComputeElementNormalVec(ELEMENT *Elem, DOUBLE *NormalVec);
// 计算elem的边界长度h, 按局部编号顺序存储到hEdge
// 计算elem的尺度h，存储到hElem
void ComputeElementInfo(ELEMENT *Elem, DOUBLE *hEdge, DOUBLE *SEdge, DOUBLE *hElem);

// 计算if_line_positive 判断单元中线的方向和线的全局方向是否一致
// void ComputeElementLineDirection(MESH *mesh, INT Index, ELEMENT *Elem);
DOUBLE ComputeAreaByCoord(DOUBLE **Coord, INT worlddim);

#endif